package org.myspringmvc.web.servlet;

import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.myspringmvc.web.constant.SystemConstant;
import org.myspringmvc.web.context.WebApplicationContext;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * @author 莫磊
 * @date 2025/8/12
 * @description 框架的核心类，处理request请求的业务逻辑，对其进行分发控制
 */
@Slf4j
public class DispatcherServlet extends HttpServlet {

    private List<HandlerAdapter> handlerAdapters = new ArrayList<>();

    private List<HandlerMapping> handlerMappings = new ArrayList<>();

    private List<ViewResolver> viewResolvers = new ArrayList<>();
    /**
     * 初始化IoC容器
     * @throws ServletException
     */
    @Override
    public void init() throws ServletException {
        // 该对象由tomcat创建,并将其传递给init(servletConfig config)方法
        ServletConfig servletConfig = getServletConfig();
        String contextConfigLocation = servletConfig.getInitParameter(SystemConstant.CONTEXT_CONFIG_LOCATION);
        log.debug("初始化IoC容器，contextConfigLocation：{}", contextConfigLocation);
        // 判断是否为类路径
        String configPath = null;
        if (contextConfigLocation.trim().startsWith(SystemConstant.PREFIX_CLASSPATH)) {
            configPath = Thread.currentThread().getContextClassLoader().getResource(contextConfigLocation.trim().substring(SystemConstant.PREFIX_CLASSPATH.length())).getPath();
            // 进行解码操作，对路径中的特殊字符进行处理
            configPath = URLDecoder.decode(configPath, StandardCharsets.UTF_8);
            log.debug("springMVC的配置文件绝对路径，contextConfigLocation：{}", configPath);
        }

        // 初始化spring web的IoC容器（web项目用的是WebApplicationContext，spring的话是ApplicationContext）
        // WebApplicationContext比ApplicationContex多了一个属性，就是ServletContext
        WebApplicationContext webApplicationContext = new WebApplicationContext(configPath, getServletContext());
        // 将webApplicationContext放入servletContext对象，方便后续的使用
        getServletContext().setAttribute(SystemConstant.WEB_APPLICATION_CONTEXT, webApplicationContext);

        // 初始化处理器映射器
        this.handlerMappings.addAll((List<HandlerMapping>) webApplicationContext.getBeansOfType(HandlerMapping.class));
        // 初始化处理器适配器
        this.handlerAdapters.addAll((List<HandlerAdapter>) webApplicationContext.getBeansOfType(HandlerAdapter.class));
        // 初始化视图解析器
        this.viewResolvers.addAll((List<ViewResolver>) webApplicationContext.getBeansOfType(ViewResolver.class));

        // 初始化拦截器，放入servletContent中
        this.getServletContext().setAttribute(SystemConstant.INTERCEPTORS, webApplicationContext.getBeansOfType(HandlerInterceptor.class));
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            doDispatch(req, resp);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void doDispatch(HttpServletRequest request, HttpServletResponse response){




        try {
            // 根据请求对象获取对应的处理器执行链
            HandlerExecutionChain mappedHandler = getHandler(request);

            // 根据处理器方法获取对应的处理器适配器
            HandlerAdapter handlerAdapter = getHandlerAdapter(mappedHandler.getHandler());

            // 根据处理器方法执行对应的拦截器preHandle方法
            if (!mappedHandler.applyPreHandle(request, response)) {
                return;
            }

            // 根据处理器适配器执行处理器方法，并返回ModelAndView
            ModelAndView mv = handlerAdapter.handle(request, response, mappedHandler.getHandler());

            // 执行postHandle方法
            mappedHandler.applyPostHandle(request, response);

            // 进行视图渲染（响应）,获取视图对象
            // 通过视图解析器进行解析，返回View对象
            View view = resolveViewName(mv.getView().toString(), Locale.CHINA);

            view.render(mv.getModel(), request, response);

            // 执行afterCompletion方法
            mappedHandler.afterCompletion(request, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }












    }

    /**
     * 根据视图名称获取对应的View对象
     * @param string 逻辑视图名
     * @param locale 本地化
     * @return
     * @throws Exception
     */
    private View resolveViewName(String string, Locale locale) throws Exception {
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(string, locale);
            if (view != null) {
                return view;
            }
        }
        return null;
    }

    private HandlerAdapter getHandlerAdapter(Object handler) {
        if (!this.handlerAdapters.isEmpty()) {
            for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
                if (handlerAdapter.supports(handler)) {
                    return handlerAdapter;
                }
            }
        }
        return null;
    }

    /**
     * 根据request获取对应的HandlerMapping，让后获取对应的HandlerExecutionChain
     * @param request
     * @return
     */
    private HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // 根据具体的request获取对应的HandlerMapping
        if (!this.handlerMappings.isEmpty()) {
            HandlerExecutionChain handler;
            for (HandlerMapping handlerMapping : this.handlerMappings) {
                handler = handlerMapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }
}
